const fs = require('fs')
const path = require('path')
const Koa = require('koa')
const compilerSfc = require('@vue/compiler-sfc') // .vue
const compilerDom = require('@vue/compiler-dom') // 模板

const app = new Koa()

/**
 * 把代码文件中的 'lib_name' 或 "lib_name" 导入，都替换成 '/@modules/lib_name'
 * @param {String} content 文件内容
 * @returns 
 */
function rewriteImport(content) {
  return content.replace(/ from ['|"]([^'"]+)['|"]/g, function (s0, s1) {
    // . ../ /开头的，都是相对路径
    if (s1[0] !== '.' && s1[1] !== '/') {
      return `from '/@modules/${s1}'`
    } else {
      return s0
    }
  })
}

app.use(async ctx => {
  const { request: { url, query } } = ctx
  
  if (url == '/') { // 首页
    ctx.type = "text/html"
    let content = fs.readFileSync('./index.html', 'utf-8')
    // 向客户端注入代码：环境变量
    content = content.replace('<script ', `
      <script>
        window.process = {env:{ NODE_ENV:'dev'}}
      </script>
      <script 
    `)
    ctx.body = content

  } else if (url.endsWith('.js')) { // 解析 js 文件导入
    // js文件
    const p = path.resolve(__dirname, url.slice(1))
    ctx.type = 'application/javascript'
    const content = fs.readFileSync(p, 'utf-8')
    ctx.body = rewriteImport(content)

  } else if (url.endsWith('.css')) { // 解析 css 文件导入
    const p = path.resolve(__dirname, url.slice(1))
    const file = fs.readFileSync(p, 'utf-8')
    const content = `
      const css = "${file.replace(/\n/g, '')}"
      let link = document.createElement('style')
      link.setAttribute('type', 'text/css')
      document.head.appendChild(link)
      link.innerHTML = css
      export default css`

    ctx.type = 'application/javascript'
    ctx.body = content

  } else if (url.startsWith('/@modules/')) { // 解析 node_module 导入
    const moduleName = url.replace('/@modules/', '')
    const prefix = path.resolve(__dirname, 'node_modules', moduleName)
    const module = require(prefix + '/package.json').module // es6 模块的入口
    const p = path.resolve(prefix, module)
    const ret = fs.readFileSync(p, 'utf-8')
    ctx.type = 'application/javascript'
    ctx.body = rewriteImport(ret)

  } else if (url.indexOf('.vue') > -1) { // 解析 .vue 单文件组件导入
    const p = path.resolve(__dirname, url.split('?')[0].slice(1))
    // 借用 vue 的 compile 框架解析单文件组件，其实相当于 vue-loader 做的事情
    const { descriptor } = compilerSfc.parse(fs.readFileSync(p, 'utf-8'))

    if (!query.type) {
      ctx.type = 'application/javascript'
      let content = rewriteImport(descriptor.script.content.replace('export default ', 'const __script = '))
      ctx.body = `${content}
        import { render as __render } from "${url}?type=template"
        __script.render = __render
        export default __script`

    } else if (query.type === 'template') { // 编译模板内容，返回 render 函数
      const template = descriptor.template
      const render = compilerDom.compile(template.content, { mode: "module" }).code
      ctx.type = 'application/javascript'
      ctx.body = rewriteImport(render)
    }
  }
})

app.listen(2333, () => { 
  console.log('Server running at http://localhost:2333') 
})
